package com.brh.druidtest.config;

import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.alibaba.druid.support.json.JSONWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.springframework.context.annotation.Configuration;

import java.io.InputStream;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.NClob;

/**
 * 慢sql拦截器
 *
 * @author BRH
 */
@Slf4j
@Configuration
public class SlowSqlFilter extends FilterEventAdapter implements Interceptor {

    private StatementProxy statement1;

    // 3 seconds is slow sql
    protected long slowSqlMillis = 3 * 1000;

    protected boolean logSlowSql;

    protected String slowSqlLogLevel = "ERROR";

    private void getStatementProxy(StatementProxy statement) {
        statement1 = statement;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        final long nowNano = System.nanoTime();
        final long nanos = nowNano - statement1.getLastExecuteStartNano();

        long millis = nanos / (1000 * 1000);
        if (millis >= slowSqlMillis) {
            String slowParameters = buildSlowParameters(statement1);
            String lastExecSql = statement1.getLastExecuteSql();
            if (logSlowSql) {
                String msg = "slow sql " + millis + " millis. " + lastExecSql + "" + slowParameters;
                switch (slowSqlLogLevel) {
                    case "WARN":
                        log.warn(msg);
                        break;
                    case "INFO":
                        log.info(msg);
                        break;
                    case "DEBUG":
                        log.debug(msg);
                        break;
                    default:
                        log.error(msg);
                }
            }
        }

        return null;
    }

    protected String buildSlowParameters(StatementProxy statement) {
        JSONWriter out = new JSONWriter();

        out.writeArrayStart();
        for (int i = 0, parametersSize = statement.getParametersSize(); i < parametersSize; ++i) {
            JdbcParameter parameter = statement.getParameter(i);
            if (i != 0) {
                out.writeComma();
            }
            if (parameter == null) {
                continue;
            }

            Object value = parameter.getValue();
            if (value == null) {
                out.writeNull();
            } else if (value instanceof String) {
                String text = (String) value;
                if (text.length() > 100) {
                    out.writeString(text.substring(0, 97) + "...");
                } else {
                    out.writeString(text);
                }
            } else if (value instanceof Number) {
                out.writeObject(value);
            } else if (value instanceof java.util.Date) {
                out.writeObject(value);
            } else if (value instanceof Boolean) {
                out.writeObject(value);
            } else if (value instanceof InputStream) {
                out.writeString("<InputStream>");
            } else if (value instanceof NClob) {
                out.writeString("<NClob>");
            } else if (value instanceof Clob) {
                out.writeString("<Clob>");
            } else if (value instanceof Blob) {
                out.writeString("<Blob>");
            } else {
                out.writeString('<' + value.getClass().getName() + '>');
            }
        }
        out.writeArrayEnd();

        return out.toString();
    }


}
